package com.unicloud.medical.oss.client;

import com.unicloud.medical.oss.client.properties.OSSClientProperties;
import com.unicloud.medical.oss.common.AbstractOSSService;
import com.unicloud.medical.oss.common.ExtEndpoint;
import com.unicloud.medical.oss.common.OSSService;
import com.unicloud.medical.oss.common.enums.ErrorEnum;
import com.unicloud.medical.oss.common.model.BucketInfo;
import com.unicloud.medical.oss.common.model.DownloadObject;
import com.unicloud.medical.oss.common.model.ObjectInfo;
import com.unicloud.medical.oss.common.model.request.*;
import com.unicloud.medical.oss.common.util.FileUtil;
import com.unicloud.medical.oss.core.OSSServiceFinder;
import com.unisound.medical.common.model.dto.ResultDTO;
import com.unisound.medical.common.util.AssertUtil;
import com.unisound.medical.common.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public abstract class BaseOSSClient implements ExtEndpoint {
    private final OSSClientProperties ossClientProperties;
    private final OSSServiceFinder ossServiceFinder;

    public BaseOSSClient(OSSClientProperties ossClientProperties, OSSServiceFinder ossServiceFinder) {
        this.ossClientProperties = ossClientProperties;
        this.ossServiceFinder = ossServiceFinder;
    }

    public OSSClientProperties getOssClientProperties() {
        return ossClientProperties;
    }

    private void fill(CommonRequest request) {
        if (StringUtils.isEmpty(request.getOssName())) {
            request.setOssName(ossClientProperties.getOssName());
        }
    }

    private BaseOSSClient proxy() {
        return SpringUtil.getBean(this.getClass());
    }

    /**
     * 查看存储桶是否存在
     */
    @Override
    public ResultDTO<Boolean> bucketExist(BucketExistRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doBucketExist(request);
    }

    protected ResultDTO<Boolean> doBucketExist(BucketExistRequest request) {
        return null;
    }

    public final ResultDTO<Boolean> execBucketExist(BucketExistRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).bucketExist(request));
    }

    public ResultDTO<Boolean> bucketExistFallback(BucketExistRequest request, Exception e) {
        return execBucketExist(request);
    }

    /**
     * 创建存储桶
     */
    @Override
    public ResultDTO<Boolean> createBucket(CreateBucketRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doCreateBucket(request);
    }

    public final ResultDTO<Boolean> execCreateBucket(CreateBucketRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).createBucket(request));
    }

    protected ResultDTO<Boolean> doCreateBucket(CreateBucketRequest request) {
        return null;
    }

    public ResultDTO<Boolean> createBucketFallback(CreateBucketRequest request, Exception e) {
        return execCreateBucket(request);
    }

    /**
     * 创建默认权限存储桶(默认策略支持浏览器直接访问url)
     */
    @Override
    public ResultDTO<Boolean> createDefaultPolicyBucket(CreateBucketRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doCreateDefaultPolicyBucket(request);
    }

    protected ResultDTO<Boolean> doCreateDefaultPolicyBucket(CreateBucketRequest request) {
        return null;
    }

    public final ResultDTO<Boolean> execCreateDefaultPolicyBucket(CreateBucketRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).createDefaultPolicyBucket(request));
    }
    
    public ResultDTO<Boolean> createDefaultPolicyBucketFallback(CreateBucketRequest request, Exception e) {
        return execCreateDefaultPolicyBucket(request);
    }

    /**
     * 删除存储桶
     */
    @Override
    public ResultDTO<Boolean> removeBucket(DeleteBucketRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doRemoveBucket(request);
    }

    public final ResultDTO<Boolean> execRemoveBucket(DeleteBucketRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).removeBucket(request));
    }

    protected ResultDTO<Boolean> doRemoveBucket(DeleteBucketRequest request) {
        return null;
    }

    public ResultDTO<Boolean> removeBucketFallback(DeleteBucketRequest request, Exception e) {
        return execRemoveBucket(request);
    }

    /**
     * 获取全部存储桶
     */
    @Override
    public ResultDTO<List<BucketInfo>> getAllBuckets(CommonRequest request) {
        fill(request);
        return proxy().doGetAllBuckets(request);
    }

    public final ResultDTO<List<BucketInfo>> execGetAllBuckets(CommonRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).getAllBuckets());
    }

    protected ResultDTO<List<BucketInfo>> doGetAllBuckets(CommonRequest request) {
        return null;
    }

    public ResultDTO<List<BucketInfo>> getAllBucketsFallback(CommonRequest request, Exception e) {
        return execGetAllBuckets(request);
    }

    /**
     * 获取当前存储桶所有文件
     */
    @Override
    public ResultDTO<List<ObjectInfo>> listAllObjectsCurrBucket(ListAllObjectsCurrBucketRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doListAllObjectsCurrBucket(request);
    }

    protected ResultDTO<List<ObjectInfo>> doListAllObjectsCurrBucket(ListAllObjectsCurrBucketRequest request) {
        return null;
    }

    public final ResultDTO<List<ObjectInfo>> execListAllObjectsCurrBucket(ListAllObjectsCurrBucketRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).listAllObjects(request));
    }

    public ResultDTO<List<ObjectInfo>> listAllObjectsCurrBucketFallback(ListAllObjectsCurrBucketRequest request, Exception e) {
        return execListAllObjectsCurrBucket(request);
    }

    /**
     * 获取当前存储桶当前文件夹所有文件
     */
    @Override
    public ResultDTO<List<ObjectInfo>> listObjectsCurrBucketAndFolder(ListAllObjectsCurrBucketAndFolderRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doListObjectsCurrBucketAndFolder(request);
    }

    protected ResultDTO<List<ObjectInfo>> doListObjectsCurrBucketAndFolder(ListAllObjectsCurrBucketAndFolderRequest request) {
        return null;
    }

    public final ResultDTO<List<ObjectInfo>> execListObjectsCurrBucketAndFolder(ListAllObjectsCurrBucketAndFolderRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).listObjects(request));
    }

    public ResultDTO<List<ObjectInfo>> listObjectsCurrBucketAndFolderFallback(ListAllObjectsCurrBucketAndFolderRequest request, Exception e) {
        return execListObjectsCurrBucketAndFolder(request);
    }

    @Override
    public ResultDTO<String> uploadObject(InnerUploadObjectRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doUploadObject(request);
    }

    protected ResultDTO<String> doUploadObject(InnerUploadObjectRequest request) {
        return null;
    }

    public final ResultDTO<String> execUploadObject(InnerUploadObjectRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).uploadObject(request));
    }
    
    public ResultDTO<String> uploadObjectFallback(InnerUploadObjectRequest request, Exception e) {
        return execUploadObject(request);
    }

    /**
     * 文件上传
     */
    @Override
    public ResultDTO<String> uploadObject(UploadObjectRequest request) {
        InnerUploadObjectRequest innerUploadObjectRequest = new InnerUploadObjectRequest(request.getBucketName(), request.getObjectName(), FileUtil.multipartFileToMeta(request.getFile()));
        innerUploadObjectRequest.setOssName(request.getOssName());
        return proxy().uploadObject(innerUploadObjectRequest);
    }

    /**
     * 批量文件上传
     */
    @Override
    public ResultDTO<List<String>> uploadObjects(InnerUploadObjectsRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doUploadObjects(request);
    }

    protected ResultDTO<List<String>> doUploadObjects(InnerUploadObjectsRequest request) {
        return null;
    }

    public final ResultDTO<List<String>> execUploadObjects(InnerUploadObjectsRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).uploadObjects(request));
    }
    
    public ResultDTO<List<String>> uploadObjectsFallback(InnerUploadObjectsRequest request, Exception e) {
        return execUploadObjects(request);
    }

    @Override
    public ResultDTO<List<String>> uploadObjects(UploadObjectsRequest request) {
        InnerUploadObjectsRequest innerUploadObjectsRequest = new InnerUploadObjectsRequest(request.getBucketName(), request.getFolder(), FileUtil.multipartFilesToMetas(request.getFiles()));
        innerUploadObjectsRequest.setOssName(request.getOssName());
        return proxy().uploadObjects(innerUploadObjectsRequest);
    }


    @Override
    public ResultDTO<String> uploadLocalObject(UploadLocalObjectRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doUploadLocalObject(request);
    }

    protected ResultDTO<String> doUploadLocalObject(UploadLocalObjectRequest request) {
        return null;
    }

    public final ResultDTO<String> execUploadLocalObject(UploadLocalObjectRequest request) {
        OSSService ossService = ossServiceFinder.find(request.getOssName());
        AssertUtil.assertTrue(ossService instanceof AbstractOSSService, ErrorEnum.UPLOAD_LOCAL_FILE_FAIL);

        Boolean success = ossService.uploadLocalObject(request.getBucketName(), request.getObjectName(), request.getFileName());
        AssertUtil.assertTrue(BooleanUtils.isTrue(success), ErrorEnum.UPLOAD_LOCAL_FILE_FAIL);

        return ResultDTO.success(ossService.accessUrl(request.getBucketName(), request.getObjectName()));
    }

    public ResultDTO<String> uploadLocalObjectFallback(UploadLocalObjectRequest request, Exception e) {
        return execUploadLocalObject(request);
    }

    /**
     * 批量本地文件上传
     */
    @Override
    public ResultDTO<List<String>> uploadLocalObjects(UploadLocalObjectsRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doUploadLocalObjects(request);
    }

    protected ResultDTO<List<String>> doUploadLocalObjects(UploadLocalObjectsRequest request) {
        return null;
    }

    public final ResultDTO<List<String>> execUploadLocalObjects(UploadLocalObjectsRequest request) {
        OSSService ossService = ossServiceFinder.find(request.getOssName());
        AssertUtil.assertTrue(ossService instanceof AbstractOSSService, ErrorEnum.UPLOAD_LOCAL_FILE_FAIL);

        List<String> urls = new ArrayList<>();
        for (String fileName : request.getFileNames()) {
            File file = new File(fileName);
            if (!FileUtil.validFile(file)) continue;

            String objectName = request.getFolder() + "/" + file.getName();
            Boolean success = ossService.uploadLocalObject(request.getBucketName(), objectName, fileName);
            AssertUtil.assertTrue(BooleanUtils.isTrue(success), ErrorEnum.UPLOAD_LOCAL_FILE_FAIL);

            if (BooleanUtils.isTrue(success)) {
                urls.add(ossService.accessUrl(request.getBucketName(), objectName));
            }
        }

        AssertUtil.assertTrue(CollectionUtils.isNotEmpty(urls), ErrorEnum.UPLOAD_FILES_FAIL);
        return ResultDTO.success(urls);
    }

    public ResultDTO<List<String>> uploadLocalObjectsFallback(UploadLocalObjectsRequest request, Exception e) {
        return execUploadLocalObjects(request);
    }

    /**
     * 文件下载
     */
    @Override
    public ResultDTO<DownloadObject> downloadObject(DownloadObjectRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doDownloadObject(request);
    }

    protected ResultDTO<DownloadObject> doDownloadObject(DownloadObjectRequest request) {
        return null;
    }

    public final ResultDTO<DownloadObject> execDownloadObject(DownloadObjectRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).downloadObject(request));
    }

    public ResultDTO<DownloadObject> downloadObjectFallback(DownloadObjectRequest request, Exception e) {
        return execDownloadObject(request);
    }

    @Override
    public ResponseEntity<byte[]> downloadObjectToBrowser(DownloadObjectRequest request) {
        ResultDTO<DownloadObject> resultDTO = proxy().doDownloadObject(request);
        
        AssertUtil.assertTrue(ResultDTO.isSuccess(resultDTO), ErrorEnum.FILE_DOWNLOAD_FAIL);
        return FileUtil.download(resultDTO.getData());
    }

    /**
     * 下载文件夹下所有文件
     */
    @Override
    public ResultDTO<DownloadObject> downloadObjects(DownloadObjectsRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doDownloadObjects(request);
    }

    protected ResultDTO<DownloadObject> doDownloadObjects(DownloadObjectsRequest request) {
        return null;
    }

    public final ResultDTO<DownloadObject> execDownloadObjects(DownloadObjectsRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).downloadObjects(request));
    }

    public ResultDTO<DownloadObject> downloadObjectsFallback(DownloadObjectsRequest request, Exception e) {
        return execDownloadObjects(request);
    }

    /**
     * 下载文件夹下所有文件
     */
    @Override
    public ResponseEntity<byte[]> downloadObjectsToBrowser(DownloadObjectsRequest request) {
        ResultDTO<DownloadObject> resultDTO = proxy().doDownloadObjects(request);
        AssertUtil.assertTrue(ResultDTO.isSuccess(resultDTO), ErrorEnum.FILE_DOWNLOAD_FAIL_IN_FOLDER);
        return FileUtil.download(resultDTO.getData());
    }

    /**
     * 根据url地址删除文件
     */
    @Override
    public ResultDTO<String> removeObject(RemoveObjectRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doRemoveObject(request);
    }

    protected ResultDTO<String> doRemoveObject(RemoveObjectRequest request) {
        return null;
    }

    public final ResultDTO<String> execRemoveObject(RemoveObjectRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).removeObject(request));
    }

    public ResultDTO<String> removeObjectFallback(RemoveObjectRequest request, Exception e) {
        return execRemoveObject(request);
    }

    /**
     * 根据url地址列表批量删除文件
     */
    @Override
    public ResultDTO<List<String>> removeObjects(RemoveObjectsRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doRemoveObjects(request);
    }

    protected ResultDTO<List<String>> doRemoveObjects(RemoveObjectsRequest request) {
        return null;
    }

    public final ResultDTO<List<String>> execRemoveObjects(RemoveObjectsRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).removeObjects(request));
    }

    public ResultDTO<List<String>> removeObjectsFallback(RemoveObjectsRequest request, Exception e) {
        return execRemoveObjects(request);
    }

    /**
     * 删除当前桶当前文件夹所有文件
     */
    @Override
    public ResultDTO<List<String>> removeObjects(RemoveObjectsCurrBucketAndFolderRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doRemoveObjects(request);
    }

    protected ResultDTO<List<String>> doRemoveObjects(RemoveObjectsCurrBucketAndFolderRequest request) {
        return null;
    }

    public final ResultDTO<List<String>> execRemoveObjectsCurrBucketAndFolder(RemoveObjectsCurrBucketAndFolderRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).removeObjects(request));
    }

    public ResultDTO<List<String>> removeObjectsCurrBucketAndFolderFallback(RemoveObjectsCurrBucketAndFolderRequest request, Exception e) {
        return execRemoveObjectsCurrBucketAndFolder(request);
    }

    /**
     * 文件复制
     */
    @Override
    public ResultDTO<String> copyObject(CopyObjectRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doCopyObject(request);
    }

    protected ResultDTO<String> doCopyObject(CopyObjectRequest request) {
        return null;
    }

    public final ResultDTO<String> execCopyObject(CopyObjectRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).copyObject(request));
    }

    public ResultDTO<String> copyObjectFallback(CopyObjectRequest request, Exception e) {
        return execCopyObject(request);
    }

    /**
     * 已签名的地址
     */
    @Override
    public ResultDTO<String> signedUrl(SignedUrlRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doSignedUrl(request);
    }

    protected ResultDTO<String> doSignedUrl(SignedUrlRequest request) {
        return null;
    }

    public final ResultDTO<String> execSignedUrl(SignedUrlRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).signedUrl(request.getBucketName(), request.getObjectName()));
    }

    public ResultDTO<String> signedUrlFallback(SignedUrlRequest request, Exception e) {
        return execSignedUrl(request);
    }

    /**
     * 批量已签名地址
     */
    @Override
    public ResultDTO<List<String>> signedUrls(SignedUrlsRequest request) {
        fill(request);
        if (StringUtils.isEmpty(request.getBucketName())) {
            request.setBucketName(ossClientProperties.getBucketName());
        }
        return proxy().doSignedUrls(request);
    }

    protected ResultDTO<List<String>> doSignedUrls(SignedUrlsRequest request) {
        return null;
    }

    public final ResultDTO<List<String>> execSignedUrls(SignedUrlsRequest request) {
        return ResultDTO.success(ossServiceFinder.find(request.getOssName()).signedUrls(request));
    }

    public ResultDTO<List<String>> signedUrlsFallback(SignedUrlsRequest request, Exception e) {
        return execSignedUrls(request);
    }

}
